﻿using AIVision.Model.MachineModels;
using AIVision.Model.EntityModels;
using AIVision.Model.UIModels;
using AIVision.PLC.LiWi;
using ImTools;
using Prism.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace AIVision.PLC.MachineModule
{
    public class PPU
    {
        private readonly IEventAggregator eventAggregator;
        private readonly PPUStatusModel ppuStatus;
        private readonly MachineStatusModel machineStatus;
        private IntPtr _handle;
        private PLCConfigDto plcConfig;
        public Task RunTask { get; set; } = new Task(() => { });
        public bool QuLiaoWaitLocation
        {
            get {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 1, ref dpos);
                var v = dpos == plcConfig.PPURunPos2;
                ppuStatus.QuLiaoWait = v;
                return v;
            } 
        }
        public bool FangLiaoWaitLocation
        {
            get
            {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 1, ref dpos);
                var v = dpos == plcConfig.PPURunPos3;
                ppuStatus.FangLiaoWait = v;
                return v;
            }
        }

        public bool QuLiaoLocation {
            get
            {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 1, ref dpos);
                var v = dpos == plcConfig.PPURunPos1;
                ppuStatus.QuLiao = v;
                return v;
            }
        }
        public bool FangLiaoLocation
        {
            get
            {
                float dpos = 0;
                Shell.PMC_GetDpos(_handle, 1, ref dpos);
                var v = dpos == plcConfig.PPURunPos4;
                ppuStatus.FangLiao = v;
                return v;
            }
        }

        public bool XiLiaoXH
        {
            get
            {
                uint in53 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 53, ref in53);
                ppuStatus.XiLiaoXH = in53 == 1;
                return in53 == 1;
            }
        }
        public bool FangLiaoXH
        {
            get
            {
                uint in3 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 3, ref in3);
                ppuStatus.FangLiaoXH = in3 == 1;
                return in3 == 1;
            }
        }
        public bool QuLiaoXH
        {
            get
            {
                uint in2 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 2, ref in2);
                ppuStatus.QuLiaoXH=in2 == 1;
                return in2 == 1;
            }
        }
        public bool FangLiaoXianWeiXH
        {
            get
            {
                uint in1 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 1, ref in1);
                //ppuStatus.FangLiaoXH = in3 == 1;
                return in1 == 1;
            }
        }
        public bool QuLiaoXianWeiXH
        {
            get
            {
                uint in0 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 0, ref in0);
                //ppuStatus.QuLiaoXH = in2 == 1;
                return in0 == 1;
            }
        }
        public bool ZhuanTaiReday
        {
            get
            {
                int runFlag = -1;
                Shell.PMC_GetIfIdle(_handle, 0, ref runFlag);
                return runFlag == -1;
            }
        }
        public PPU(IEventAggregator eventAggregator,PPUStatusModel ppuStatus,MachineStatusModel machineStatus) 
        {
            this.eventAggregator = eventAggregator;
            this.ppuStatus = ppuStatus;
            this.machineStatus = machineStatus;
        }
        public void Init(IntPtr _handle, PLCConfigDto plcConfig)
        {
            this._handle = _handle;
            this.plcConfig = plcConfig;
        }

        public void ResetLocationAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(ResetLocation, CTS.Token);
                RunTask.Start();
            }
        }
        public void ResetLocation()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                Shell.PMC_SetOp(_handle, 0, 0);

                Shell.PMC_SetAtype(_handle, 1, 1); // 设置轴 0 轴类型为 1 
                Shell.PMC_SetInvertStep(_handle, 1, 1);
                Shell.PMC_SetUnits(_handle, 1, 10); // 设置轴 0 脉冲当量为 100 
                Shell.PMC_SetAxisEnable(_handle, 1, 1);

                Shell.PMC_SetSpeed(_handle, 1, 360);
                Shell.PMC_Single_Vmove(_handle, 1, 1);
                timeout = 0;
                while (!FangLiaoXianWeiXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 1, 3);
                Task.Delay(500).Wait();
                Shell.PMC_Single_Vmove(_handle, 1, -1);
                timeout = 0;
                while (!QuLiaoXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 1, 3);
                Shell.PMC_SetSpeed(_handle, 1, 36);
                Shell.PMC_Single_Vmove(_handle, 1, -1);
                timeout = 0;
                while (QuLiaoXH)
                    WaitTimeout(10000);
                Shell.PMC_Single_Cancel(_handle, 1, 3);
                int ret0 = Shell.PMC_SetDpos(_handle, 1, 0); // 轴指令位置清 0 
                ret0 += Shell.PMC_SetMpos(_handle, 1, 0); // 编码器反馈位置清 0 
                ret0 += Shell.PMC_SetSpeed(_handle, 1, plcConfig.PPURunSpeed); // 设置轴 0 速度为 200units/s 
                ret0 += Shell.PMC_SetAccel(_handle, 1, plcConfig.PPURunSpeed * 10); // 设置轴 0 加速度为 2000units/s/s 
                ret0 += Shell.PMC_SetDecel(_handle, 1, plcConfig.PPURunSpeed * 10); // 设置轴 0 减速度为 2000units/s/s 
                Shell.PMC_Single_MoveAbs(_handle, 1, plcConfig.PPURunPos2);
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 1, 3);
            }
        }
        public void RunQuLiaoAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(RunQuLiao, CTS.Token);
                RunTask.Start();
            }
        }
        public void RunQuLiao()
        {
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                if (QuLiaoWaitLocation)
                    Shell.PMC_Single_MoveAbs(_handle, 1, plcConfig.PPURunPos1);
                timeout = 0;
                while (!QuLiaoLocation)
                    WaitTimeout(1000);

                Shell.PMC_SetOp(_handle, 0, 1);
                while (!XiLiaoXH)
                    WaitTimeout(5000,"PPU吸料失败!");
                Task.Delay(50).Wait();
                Task.Delay(plcConfig.PPUQuDelay).Wait();
                Shell.PMC_Single_MoveAbs(_handle, 1, plcConfig.PPURunPos3);
                timeout = 0;
                while (!FangLiaoWaitLocation)
                    WaitTimeout(1000);
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 1, 3);
            }
        }
        public void RunFangLiaoAsync()
        {
            Trace.WriteLine($"ppu放料子步骤：异步启动任务条件判断:{RunTask.Status}");
            while (RunTask.Status == TaskStatus.Running)
                WaitTimeout(2000, "PPU放料Task等待超时");

            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH)
            {
                Trace.WriteLine($"ppu放料子步骤：异步启动任务");
                CTS = new CancellationTokenSource();
                RunTask = new Task(RunFangLiao, CTS.Token);
                RunTask.Start();
            }
        }
        public void RunFangLiao()
        {
            
            if (machineStatus.EmergencyStopXH)
                return;
            try
            {
                Trace.WriteLine($"ppu放料子步骤1：判断运行条件:{FangLiaoWaitLocation}&{ZhuanTaiReday}");
                if (FangLiaoWaitLocation && ZhuanTaiReday)
                {
                    Trace.WriteLine($"ppu放料子步骤2：发送pos4指令");
                    int i = Shell.PMC_Single_MoveAbs(_handle, 1, plcConfig.PPURunPos4);
                    Trace.WriteLine($"ppu放料子步骤3：指令发送完成，返回值：{i}");
                    Trace.WriteLine($"ppu放料子步骤4：等待ppu走到位置4");
                    timeout = 0;
                    while (!FangLiaoLocation)
                        WaitTimeout(1000);
                    Trace.WriteLine($"ppu放料子步骤5：ppu都在位置4，关闭吸料");
                    Shell.PMC_SetOp(_handle, 0, 0);

                    Task.Delay(plcConfig.PPUFangDelay).Wait();
                    timeout = 0;
                    Shell.PMC_Single_MoveAbs(_handle, 1, plcConfig.PPURunPos2);
                    while (!QuLiaoWaitLocation)
                        WaitTimeout(1000);
                }
            }
            catch (OperationCanceledException)
            {
                Shell.PMC_Single_Cancel(_handle, 1, 3);
            }
        }
        public void StepAsync()
        {
            if (RunTask.Status != TaskStatus.Running && !machineStatus.EmergencyStopXH && machineStatus.ResetLocationStatus)
            {
                CTS = new CancellationTokenSource();
                RunTask = new Task(Step, CTS.Token);
                RunTask.Start();
            }
        }
        public void Step()
        {
            if (machineStatus.EmergencyStopXH && !machineStatus.ResetLocationStatus)
                return;
            if (QuLiaoWaitLocation)
                RunQuLiao();
            else if (FangLiaoWaitLocation)
                RunFangLiao();
        }
       

        public void MonitorStatus()
        {
            float dpos = 0, mpos = 0, pfvalue = 0;
            int runFlag = -1;
            Shell.PMC_GetDpos(_handle, 1, ref dpos);
            Shell.PMC_GetMpos(_handle, 1, ref mpos);
            Shell.PMC_GetIfIdle(_handle, 1, ref runFlag);
            Shell.PMC_GetMspeed(_handle, 1, ref pfvalue);
            ppuStatus.DPos = dpos;
            ppuStatus.MPos = mpos;
            ppuStatus.RunFlag = runFlag == 0 ? true : false;
            ppuStatus.Speed = pfvalue;

            var v = QuLiaoWaitLocation;
            v = FangLiaoWaitLocation;
            v = QuLiaoLocation;
            v = FangLiaoLocation;
            v = QuLiaoXH;
            v = QuLiaoXH;
            v = XiLiaoXH;
        }


        #region WaitTimeout
        public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
        public delegate void TimeOutDelegate();
        private int timeout = 0;
        private void WaitTimeout(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}","Red"));
            }
        }
        #endregion
    }
}
